#include "StdAfx.h"
#include "MagicCubeGame.h"


MagicCubeGame::MagicCubeGame(void)
{
	this->lock=new CCriticalSection();
	this->magic=new MagicCube(0.0f,0.0f,0.0f,2.0f);
	this->operationList=new std::queue<MagicCubeOperation*>();
	this->operationHistory=new std::stack<MagicCubeOperation*>();
	this->functions=new std::list<DrawFuncInfo*>();
	this->gamePattern=HANDEL;
	this->isStopRandom=false;
}

bool MagicCubeGame::CheckMovingStatus()
{
	if(this->operationList->empty())
		return false;
}

void MagicCubeGame::Render(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//this->DrawXYZ();
	switch(this->gamePattern)
	{
	case HANDEL:
		this->HandelOperation();
		break;
	case RANDOM:
		this->RandomOperation();
		break;
	default:
		break;
	}

	std::list<DrawFuncInfo*>::iterator iter;
	for(iter=this->functions->begin();iter!=this->functions->end();iter++)
	{
		(((*iter)->pClass)->*((*iter)->func))((*iter)->x,(*iter)->y,(*iter)->z);
	}
	glFlush();
}

void MagicCubeGame::AddDrawObject(DrawFuncInfo* info)
{
	this->functions->push_back(info);
}

void MagicCubeGame::SetMagicPosition(GLfloat x,GLfloat y,GLfloat z)
{
	this->magic->TransformWorldPosition(x,y,z);
}

void MagicCubeGame::SetGamePattern(GamePattern pattern)
{
	this->gamePattern=pattern;
}

void MagicCubeGame::RotateWorld(GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
{
	this->magic->AddWoirdRotation(angle,x,y,z);
}

void MagicCubeGame::AddOperation(MagicCubeOperation* operation)
{
	lock->Lock();
	this->operationList->push(operation);
	lock->Unlock();
}

void MagicCubeGame::RandomOperation()
{
	this->lock->Lock();
	if(this->operationList->empty())
	{
		this->magic->Draw(
			0.0f,0.0f,0.0f,
			0.0f,
			0.0
			);
		if(!this->isStopRandom)
			this->operationList->push(this->GetRandomOperation());
	}
	else
	{
		this->magic->Draw(
			this->operationList->front()->vx,
			this->operationList->front()->vy,
			this->operationList->front()->vz,
			this->operationList->front()->index,
			this->operationList->front()->angel
			);

		if(this->operationList->front()->angel==90||this->operationList->front()->angel==-90)
		{
			MagicCubeOperation* job=this->operationList->front();
			job->angel=0;
			this->operationList->pop();
			if(job->operationFrom!=2)
			{
				job->operationFrom=2;
				this->operationHistory->push(job);
			}
		}
		else
		{
			this->operationList->front()->angel+=(operationList->front()->add);
		}
	}
	this->lock->Unlock();
}

void MagicCubeGame::HandelOperation()
{
	this->lock->Lock();
	if(!this->operationList->empty())
	{
		this->magic->Draw(
			this->operationList->front()->vx,
			this->operationList->front()->vy,
			this->operationList->front()->vz,
			this->operationList->front()->index,
			this->operationList->front()->angel
			);

		if(this->operationList->front()->angel==90||this->operationList->front()->angel==-90)
		{
			MagicCubeOperation* job=this->operationList->front();
			job->angel=0;
			this->operationList->pop();
			if(job->operationFrom!=2)
			{
				job->operationFrom=2;
				this->operationHistory->push(job);
			}
		}
		else
		{
			this->operationList->front()->angel+=(operationList->front()->add);
		}
	}
	else
	{
		this->magic->Draw(
			0.0f,0.0f,0.0f,
			0.0f,
			0.0
			);
	}
	this->lock->Unlock();
}

void MagicCubeGame::DrawXYZ(void)
{
	glLoadIdentity();

	glBegin(GL_LINES);
	glVertex3f(-5.0f, 0.0f, 0.0f);  
	glVertex3f(100.0f, 0.0f, 0.0f);
	glEnd();

	glBegin(GL_LINES);
	glVertex3f(0.0f, -5.0f, 0.0f);  
	glVertex3f(0.0f, 100.0f, 0.0f);
	glEnd();

	glBegin(GL_LINES);
	glVertex3f(0.0f, 0.0f, -5.0f);  
	glVertex3f(0.0f, 0.0f, 100.0f);  
	glEnd();

}

MagicCubeOperation* MagicCubeGame::GetRandomOperation()
{
	int index=rand()%3;
	int direction=(rand()%2==0)?1:-1;
	int value=rand()%3;
	GLfloat x=0.0f;
	GLfloat y=0.0f;
	GLfloat z=0.0f;
	if(0==value) x=1.0f;
	else if(1==value) y=1.0f;
	else z=1.0f;
	return new MagicCubeOperation(x,y,z,index,0.0f,direction);
}

MagicCubeGame::~MagicCubeGame(void)
{
	delete this->magic;
	delete this->operationList;
	delete this->operationHistory;
	delete this->lock;
}

void MagicCubeGame::StepUndo()
{
	if(this->gamePattern==HANDEL)
	{
		lock->Lock();
		if(!this->operationHistory->empty())
		{
			MagicCubeOperation* op=this->operationHistory->top();
			op->add*=-1;
			this->operationHistory->pop();
			this->operationList->push(op);
		}
		lock->Unlock();
	}
}

void MagicCubeGame::StepsUndo()
{
	if(this->gamePattern==HANDEL)
	{
		while(!this->operationHistory->empty())
		{
			lock->Lock();
			MagicCubeOperation* op=this->operationHistory->top();
			op->add*=-1;
			this->operationHistory->pop();
			this->operationList->push(op);
			lock->Unlock();
		}	
	}
}

void MagicCubeGame::Reset()
{
	lock->Lock();
	if(!this->operationList->empty())
	{
		this->operationList->front()->angel=0;
		operationList->pop();
	}
	lock->Unlock();
	this->SetGamePattern(HANDEL);
	this->magic->Reset();
}
